package sip

import (
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"strings"
	"udp_tcp_client/sip/body"
	"udp_tcp_client/sip/header"
	"udp_tcp_client/sip/header/common"
	"udp_tcp_client/util"
)

type Message struct {
	IsRequest    bool          // (二选一) 是否是请求
	IsResponse   bool          // (二选一) 是否是应答
	RequestLine  RequestLine   // 请求行
	ResponseLine ResponseLine  // 应答行
	Header       header.Header // 消息包头
	BodyIsString bool
	BodyItem     body.BodyItem
	BodyString   body.BodyString
}

type MessageParam struct {
	Method       string
	FromTag      string
	ToTag        string
	ContentType  string
	BodyIsString bool
	MessageBody  string
	CallId       string
	Cseq         int
	Network      string
}

type NewMessageParam struct {
	Method       string
	From         header.UserDomain
	To           header.UserDomain
	Ip           string
	Port         int
	ContentType  string
	BodyIsString bool
	MessageBody  string
	CallId       string
	Cseq         int
	Network      string
}

func (msg *Message) AnalyzeMessage(s string) (err error) {
	stringSlice := strings.Split(s, util.CRLF)
	if nil == stringSlice || len(stringSlice) == 0 {
		logrus.Errorln("数据切割失败, s : ", s)
		return errors.New("数据切割失败")
	}

	//解析主题
	firstLine := stringSlice[0]
	length := len(firstLine)
	if 0 == length || !strings.Contains(firstLine, util.SIPVersion) {
		logrus.Errorln("不是SIP协议, s : ", s)
		return errors.New("不是SIP协议")
	}
	if util.SIPVersion == firstLine[0:7] {
		responseLine := ResponseLine{}
		err = responseLine.parse(stringSlice[0])
		msg.ResponseLine = responseLine
		msg.IsResponse = true
	} else {
		requestLine := RequestLine{}
		err = requestLine.parse(stringSlice[0])
		if err != nil {
			return err
		}
		msg.RequestLine = requestLine
		msg.IsRequest = true
	}

	//解析头
	h := header.Header{}
	i, err := h.AnalyzeMessage(stringSlice)
	if err != nil {
		logrus.Errorln("解析头失败, err : ", err)
		return errors.New("解析头失败")
	}
	msg.Header = h

	//解析body
	if strings.Contains(stringSlice[i+1], "?xml") {
		b := body.BodyString{}
		sb := strings.Builder{}

		for j := i + 1; j < len(stringSlice); j++ {
			sb.WriteString(stringSlice[j])
		}
		err = b.NewBodyString(sb.String())
		if err != nil {
			logrus.Errorln("解析body失败, err : ", err)
			return errors.New("解析body失败")
		}
		msg.BodyString = b
		msg.BodyIsString = true
	} else {
		b := body.BodyItem{}
		err = b.NewBodyStringArray(stringSlice, i+1)
		if err != nil {
			logrus.Errorln("解析body失败, err : ", err)
			return errors.New("解析body失败")
		}
		msg.BodyItem = b
		msg.BodyIsString = false
	}

	logrus.Infoln("解析完毕  ")
	for i, s := range stringSlice {
		logrus.Infoln(i, s)
	}

	return nil
}

func (msg *Message) NewMessage(param *NewMessageParam) error {
	msg.IsRequest = true

	//创建主题
	line, err := NewRequestLine(param.Method, param.To.Username(), param.Ip+":"+fmt.Sprintf("%d", param.Port), common.Args{})
	if err != nil {
		return err
	}
	msg.RequestLine = line

	//创建头
	viaList := header.ViaList{}

	via, err := header.NewVia(util.Conf.Sip.IP+util.COLON+fmt.Sprintf("%d", util.Conf.Sip.Port), param.Network, common.ParseArgs(util.ArgRport+util.BRANCH+util.ArgBranch+util.EQUAL+"z9hG4bK-"+util.RandomUUidWithoutDash()))
	if err != nil {
		return err
	}
	err = viaList.Add(via)
	if err != nil {
		return err
	}

	from := param.From
	to := param.To

	contact, err := header.NewUserIpPort(param.To.DisplayName, param.To.Username(), util.Conf.Sip.IP, util.Conf.Sip.Port, common.Args{})
	if err != nil {
		return err
	}

	m, err := header.NewCSeq(param.Cseq, param.Method)
	if err != nil {
		return err
	}

	forwards, err := header.NewMaxForwards(70)
	if err != nil {
		return err
	}

	newHeader, err := header.NewHeader(viaList, from, to, &contact, param.CallId, m, forwards)
	newHeader.AddUserAgent(util.Conf.Sip.UserAgent)

	if "" != param.MessageBody {
		newHeader.AddContentType(param.ContentType)
		msg.BodyIsString = param.BodyIsString
		if param.BodyIsString {
			b := body.BodyString{}
			err = b.NewBodyString(param.MessageBody)
			if err != nil {
				return err
			}
			msg.BodyString = b
		} else {
			b := body.BodyItem{}
			err = b.NewBoadyItem(param.MessageBody)
			if err != nil {
				return err
			}
			msg.BodyItem = b
		}
	}
	msg.Header = newHeader
	return nil
}

func (msg *Message) AddSdp(sdp string) {
	msg.Header.ContentType = util.ContentTypeSdp
	msg.BodyIsString = false
	b := body.BodyItem{}
	b.NewBoadyItem(sdp)
	msg.BodyItem = b
}

func (msg *Message) IncCsq() {
	msg.Header.CSeq.CSeq++
}

// 字符串表示
func (msg *Message) String() (result string) {
	// 输出首行
	if msg.IsRequest {
		result += msg.RequestLine.String()
	} else {
		result += msg.ResponseLine.String()
	}
	result += util.CRLF
	// 更新内容长度
	var bodyString string
	if msg.BodyIsString {
		bodyString = msg.BodyString.String()
	} else {
		bodyString = msg.BodyItem.String()
	}

	msg.Header.ContentLength = len(bodyString)
	// 写入Header
	result += msg.Header.String()
	// 写入分隔的空行
	result += util.CRLF
	// 写入Body
	result += bodyString
	return
}

type Device struct {
	Id       int
	DeviceId string
	Port     int
	Ip       string
}

func (msg *Message) NewDeviceMessage(param *MessageParam, device *Device) error {
	msg.IsRequest = true

	//创建主题
	line, err := NewRequestLine(param.Method, device.DeviceId, device.Ip+":"+fmt.Sprintf("%d", device.Port), common.Args{})
	if err != nil {
		return err
	}
	msg.RequestLine = line

	//创建头
	viaList := header.ViaList{}

	via, err := header.NewVia(util.Conf.Sip.IP+":"+fmt.Sprintf("%d", util.Conf.Sip.Port), param.Network, common.ParseArgs(util.ArgRport+util.BRANCH+util.ArgBranch+util.EQUAL+"z9hG4bK-"+util.RandomUUidWithoutDash()))
	if err != nil {
		return err
	}
	err = viaList.Add(via)
	if err != nil {
		return err
	}

	fromArgs := common.Args{}
	if param.FromTag != "" {
		fromArgs = common.ParseArgs(param.FromTag)
	}
	from, err := header.NewUserDomain(util.Conf.Sip.UserName, util.Conf.Sip.UserName, util.Conf.Sip.IP+util.COLON+fmt.Sprintf("%d", util.Conf.Sip.Port), fromArgs)
	if err != nil {
		return err
	}

	toArgs := common.Args{}
	if param.ToTag != "" {
		toArgs = common.ParseArgs(param.ToTag)
	}
	to, err := header.NewUserDomain(device.DeviceId, device.DeviceId, device.Ip+util.COLON+fmt.Sprintf("%d", device.Port), toArgs)
	if err != nil {
		return err
	}

	contact, err := header.NewUserIpPort(util.Conf.Sip.UserName, util.Conf.Sip.UserName, util.Conf.Sip.IP, util.Conf.Sip.Port, common.Args{})
	if err != nil {
		return err
	}

	m, err := header.NewCSeq(param.Cseq, param.Method)
	if err != nil {
		return err
	}

	forwards, err := header.NewMaxForwards(70)
	if err != nil {
		return err
	}

	newHeader, err := header.NewHeader(viaList, from, to, &contact, param.CallId, m, forwards)
	newHeader.AddUserAgent(util.Conf.Sip.UserAgent)

	if "" != param.MessageBody {
		newHeader.AddContentType(param.ContentType)
		msg.BodyIsString = param.BodyIsString
		if param.BodyIsString {
			b := body.BodyString{}
			err = b.NewBodyString(param.MessageBody)
			if err != nil {
				return err
			}
			msg.BodyString = b
		} else {
			b := body.BodyItem{}
			err = b.NewBoadyItem(param.MessageBody)
			if err != nil {
				return err
			}
			msg.BodyItem = b
		}
	}
	msg.Header = newHeader
	return nil
}
